#include "../include/ThreadCache.h"
#include "../include/CentralCache.h"

namespace My_MemoryPool
{
    void * ThreadCache::allocate(size_t size)
    {
        // 处理0大小的分配表
        if(size == 0)
        {
            size = ALIGNMENT;
        }
        if(size>MAX_BYTES)
        {
            //大对象直接从系统分配
            return malloc(size);
        }

        size_t index = SizeClass::getIndex(size);

        //更新自由链表大小
        freeListSize_[index]--;
        //检查线程本地自由链表
        //如果freeList_[index] 不为空，表示该链表中有可用的内存块
        if(void * ptr =freeList_[index])
        {
            // 将freeList_[index]指向的内存块的下一个内存块地址（取决于内存块的实现）
            /*
                ptr 是当前要分配的内存块的地址（链表头）。

                这个内存块的前 sizeof(void*) 字节保存了下一个内存块的地址。

                reinterpret_cast<void**>(ptr) 将 ptr 视为一个指向 void* 的指针（即 void**）。

                *reinterpret_cast<void**>(ptr) 解引用这个指针，得到下一个内存块的地址。

                更新 freeList_[index] 为下一个内存块的地址，完成链表头的移动。
            */
            freeList_[index] = *reinterpret_cast<void**>(ptr);
            return ptr;
        }

        // 如果线程本地自由链表为空，则从中心缓存获取一批内存
        return fetchFromCentralCache(index);
    }

    void ThreadCache::deallocate(void *ptr,size_t size)
    {
        if(size > MAX_BYTES){
            // 大对象直接返回系统
            free(ptr);
            return;
        }

        // 计算索引并插入到对应自由链表头部
        size_t index = SizeClass::getIndex(size);

        // 插入到线程本地自由链表
        // *reinterpret_cast<void**>(ptr) = freeList_[index];  -> 将当前内存块（ptr）的下一个节点设为链表的原头部。
        *reinterpret_cast<void**>(ptr) = freeList_[index];   
        freeList_[index] = ptr;  // 将链表的头部更新为当前内存块（ptr）

        // 更新自由链表大小
        freeListSize_[index]++; // 增加对应大小类的自由链表大小

        // 判断是否需要将部分内存回收给中心缓存  --> 比如说链了很多内存块
        if(shouldReturnToCentralCache(index))
        {
            returnToCentralCache(freeList_[index],size);
        }

    }

    // 判断是否需要将内存回收给内存中心
    bool ThreadCache::shouldReturnToCentralCache(size_t index)
    {
        //设定阈值，例如，当自由链表的大小超过一定数量时
        size_t threshold = 64;
        return (freeListSize_[index]>threshold);
    }

    // 从中心缓存获取内存
    void* ThreadCache::fetchFromCentralCache(size_t index)
    {
        //从中心缓存批量获取内存
        void* start = CentralCache::getInstance().fetchRange(index);
        if(!start) return nullptr;

        //去一个返回,其余放入自由链表
        void * result =start;
        freeList_[index] = *reinterpret_cast<void**>(start);

        //更新自由链表大小
        size_t batchNum = 0;
        // 从start开始遍历
        void* current = start; 

        // 计算从中心缓存获取的内存块数量
        while(current!=nullptr)
        {
            batchNum++;
            current = *reinterpret_cast<void**>(current);
        }

        // 更新freeListSize_，增加获取的内存块数量
        freeListSize_[index]+=batchNum;
        return result;
    }

    // 向中心缓存归还内存
    void ThreadCache::returnToCentralCache(void* start,size_t size)
    {
        // 根据大小计算对应的索引
        size_t index = SizeClass::getIndex(size);
        //  获取对齐后的实际块大小
        size_t alignedSize = SizeClass::roundUp(size);

        //计算要归还内存块的数量
        size_t batchNum = freeListSize_[index];
        //如果只有一个块，不归还
        if(batchNum<=1) return; 

        //保留一部分再ThreadCache中（比如保留1/4）
        size_t keepNum = std::max(batchNum/4,size_t(1));
        size_t returnNum = batchNum-keepNum;

        //将内存块串成链表
        char* current = static_cast<char*> (start);
        //使用对齐后的大小计算分割点
        char * splitNode = current;
        for(size_t i = 0 ;i<keepNum-1;i++)
        {
            splitNode = reinterpret_cast<char*>(*reinterpret_cast<void**>(splitNode));
            if(splitNode == nullptr)
            {
                //意味着提前结束
                returnNum = batchNum - (i+1);
                break;
            }
        }

        if(splitNode!=nullptr)   
        {
            // 将要返回的部分和要保留的部分断开
            void * nextNode = *reinterpret_cast<void**>(splitNode);
            *reinterpret_cast<void**>(splitNode)=nullptr; //断开连接

            //更新ThreadCache的空闲链表
            freeList_[index] = start;

            //更新自由链表大小
            freeListSize_[index]= keepNum;

            // 将剩余部分返回给CentralCache
            if(returnNum>0 && nextNode!=nullptr)
            {
                CentralCache::getInstance().returnRange(nextNode, returnNum * alignedSize, index);
            }    
        }
    }

}